<cfcomponent output="false">
		
	<!--- --->
		
	<cffunction name="it" access="public" output="false" returntype="any">
		<cfargument name="method" required="true" />
		<cfargument name="args" required="false" default="#{}#" />
		<cfargument name="log" required="false" default="false" />
		<cfargument name="ajax" required="false" default="" />
		 
		<cfset var local = {} />

		<cfset local.cfc = listGetAt(arguments.method,1,'.') />
		<cfset local.method = listGetAt(arguments.method,2,'.') />
		<cfset local.isLog = arguments.log />
		
		<cfif local.cfc contains "Service">
			<cfset local.namespace = "s" />
		<cfelseif local.cfc contains "Gateway">
			<cfset local.namespace = "g" />
		<cfelseif local.cfc contains "Controller">
			<cfset local.namespace = "c" />
		<cfelseif local.cfc contains "View">
			<cfset local.namespace = "v" />
		</cfif>
		
		<!--- attempt to run the function --->
		<cftry>
			<cfset local.returnData = application[local.namespace][local.cfc][local.method](argumentCollection=arguments.args) />
			<!--- log any errors --->
			<cfcatch>
				<cfset local.message = "$.run caught an error" />
				
				<cfset $.log.add(
					name="#arguments.ajax#error",
					message=local.message,
					method=arguments.method,
					args=arguments.args,
					cfcatch=cfcatch
				) />
				
				<!--- rethrow error if devmode --->
				<cfif application.devmode>
					<cfrethrow />
				<cfelseif local.namespace eq 'v'>
					<cfsavecontent variable="local.errorstuff">
						<div class="error-page-text" style="display:inline-block;position:static;margin:13px 5px 5px 5px;">
							<b>Oops, something didn't display correctly</b>
							</br><i class="fa fa-frown-o"></i></br>
							The development staff has been notified
							</br>and are looking for a solution
							</br></br>
							*we beg you for forgiveness*
						</div>
						<div class="error" style="display:none;">
							<cfdump var="#cfcatch#"><cfdump var="#cgi#">
						</div>
					</cfsavecontent>
					<cfreturn local.errorstuff />
				</cfif>
			</cfcatch>
		</cftry>
		
		<!--- log the function if necessary --->
		<cfif local.isLog>
			<cfset $.log.add(
				name="devlog",
				message="Logging for this function is ON",
				method=arguments.method,
				args=arguments.args
			) />
		</cfif>
		
		<!--- return any data the function call may have collected --->
		<cfif structKeyExists(local,"returnData")>
			<cfreturn local.returnData />
		<cfelse>
			<cfreturn "" />
		</cfif>
	
	</cffunction>
	
	<!--- --->
	
	<cffunction name="http" access="public" output="false" returntype="any">
		<cfargument name="url" required="true" />
		<cfargument name="args" required="false" default="#{}#" />
		<cfargument name="type" required="false" default="POST" />
		<cfargument name="authorization" required="false" default="" />
		<cfargument name="contentType" required="false" default="" />
		<cfargument name="message" required="true" />
		<cfargument name="success_codes" required="false" default="200" />

		<cfset var local = {} />
		
		<cfset local.retryCodes = "503,408" />
		<!--- on a post (create) do not retry for timeout or will get dupes --->
		<cfif arguments.type eq "POST">
			<cfset local.retryCodes = "503" />
		</cfif>
		
		<!--- set message to url if empty --->
		<cfif arguments.message eq "">
			<cfset arguments.message = arguments.url />
		</cfif>

		<cfset local.result = {
			success:false,
			outcome:"unstarted",
			params:{},
			url:arguments.url
		} />
		
		<cfif arguments.type eq 'GET'>
			<cfset arguments.url = arguments.url & '?' />
			<cfloop collection="#arguments.args#" item="local.item">
				<cfset arguments.url = arguments.url & local.item & '=' & arguments.args[local.item] & '&' />
				<cfset local.result.params[local.item] = arguments.args[local.item] />
			</cfloop>
			<cfset local.result.url = arguments.url />
		</cfif>
		
		<cfset local.result.params.type = arguments.type />

		<cftry>
			<cfset local.cfhttp = _cfhttp(argumentCollection=arguments) />
			
			<!--- try again if 503 Service unavailable --->
			<cfif structKeyExists(local.cfhttp,"status_code") and listContainsNoCase(local.retryCodes,local.cfhttp.status_code)>
				<!--- wait 5 seconds and try again --->
				<cfset local.original_code = local.cfhttp.status_code />
				<cfset sleep(5000) />
				<cfset arguments.timeout = 30 />
				<cfset local.cfhttp = _cfhttp(argumentCollection=arguments) />
				<cfset $.log.add(
					name="http_error",
					method="#arguments.message# #local.original_code# Retry #local.cfhttp.status_code#",
					args=arguments.args,
					cfcatch=local.cfhttp
				) />
			</cfif>
			
			<!--- Start setting up the response --->
			<!--- set status code --->
			<cfset local.result.cfhttp = local.cfhttp />
			<cfif structKeyExists(local.cfhttp,"statuscode")>
				<cfset local.result.outcome = cfhttp.statuscode />
			<cfelse>
				<cfset local.result.outcome = "No Statuscode" />
			</cfif>
			
			<!--- set the number code --->
			<cfif structKeyExists(local.cfhttp,"status_code")>
				<cfset local.result.status_code = local.cfhttp.status_code />
			<cfelse>
				<cfset local.result.status_code = "no status code" />
			</cfif>

			<cfif arguments.success_codes contains local.result.status_code>
				<cfset local.result.success = true />
				<!--- check filecontent exists --->
				<cfif structKeyExists(local.cfhttp,"filecontent")>
					<cfset local.result.json = deserializeJson(local.cfhttp.filecontent) />
					<cfif isStruct(local.result.json)>
						<cfloop collection="#local.result.json#" item="local.item">
							<cfset local.result[local.item] = local.result.json[local.item] />
						</cfloop>
					</cfif>
				<cfelse>
					<cfset $.log.add(
						name="http_error",
						method="#arguments.message# no filecontent",
						args=arguments.args,
						cfcatch=local.cfhttp
					)>
				</cfif>
				
			</cfif>

			<cfcatch>
				<cfset local.result.success = false />
				<cfset local.result.outcome = "http error" />
				<cfset local.result.cfcatch = cfcatch />
				<cfset arguments.args.url = arguments.url />
				
				<cfset $.log.add(
					name="http_error",
					method="#arguments.message# Error attempting HTTP",
					args=arguments.args,
					cfcatch=cfcatch
				)>
				<cfreturn local.result />
			</cfcatch>
		</cftry>
		
		<cfif not local.result.success>
			<cfset arguments.args.url = arguments.url />
			<cfset arguments.args.result = local.result />
			<cfset local.status_code = "no status_code" />
			<cfif structKeyExists(local.cfhttp,'status_code')>
				<cfset local.status_code = local.cfhttp.status_code />
			</cfif>

			<cfset $.log.add(
				name="http_error",
				method="#arguments.message# #local.status_code#",
				args=arguments.args,
				cfcatch=local.cfhttp
			) />
		</cfif>
		
		<cfreturn local.result />
	
	</cffunction>
	
	<!--- --->
	
	<cffunction name="thread" access="public" output="false" returntype="any">
		<cfargument name="method" required="true" />
		<cfargument name="args" required="false" default="#{}#" />
		<cfargument name="log" required="false" default="false" />
		
		<cfset var local = {} />

		<cfset local.cfc = listGetAt(arguments.method,1,'.') />
		<cfset local.method = listGetAt(arguments.method,2,'.') />
		<cfset local.isLog = arguments.log />
		
		<cfif local.cfc contains "Service">
			<cfset local.namespace = "s" />
		<cfelseif local.cfc contains "Gateway">
			<cfset local.namespace = "g" />
		<cfelseif local.cfc contains "Controller">
			<cfset local.namespace = "c" />
		<cfelseif local.cfc contains "View">
			<cfset local.namespace = "v" />
		</cfif>
		
		<cfset local.uuid = createUUID() />
		<cfset local.threadname = "#arguments.method##local.uuid#userID#request.session.user.id#" />
		<cfthread action="run" name="#local.threadname#" namespace="#local.namespace#" cfc="#local.cfc#" method="#local.method#" args="#arguments.args#">
			<cfset application[namespace][cfc][method](argumentCollection=args) />
		</cfthread>

		<cfset arrayAppend(application.threads,cfthread[local.threadname]) />

		<!--- log the function if necessary --->
		<cfif local.isLog>
			<cfset $.log.add(
				name="devlog",
				message="Logging for this function is ON",
				method=arguments.method & ' thread',
				args=arguments.args,
				cfcatch=cfthread[local.threadname]
			) />
		</cfif>
		
		<cfset cleanThreads() />
		
		<cfreturn true />
	
	</cffunction>
	
	<!--- --->
	
	<cffunction name="cleanThreads" access="public" output="false" returntype="string">
		
		<cfset var local = {} />
		
		<cfset local.new = [] />

		<cfloop array="#application.threads#" index="local.i" item="local.item">
			<cfif local.item.status neq 'RUNNING' or local.item.elapsedtime gt 900000>
				<cfif local.item.status neq 'COMPLETED'>
					<cfset $.log.add(
						name="thread_error",
						method=left(local.item.name,len(local.item.name)-73) & ' ' & local.item.status,
						cfcatch=local.item
					) />
				</cfif>
				<cftry>
					<cfthread action="terminate" name="#local.item.name#" />
					<cfcatch><!--- do nothing ---></cfcatch>
				</cftry>
			<cfelse>
				<cfset arrayAppend(local.new,local.item) />
			</cfif>
		</cfloop>
		
		<cfset application.threads = local.new />
				
		<cfreturn true />

	</cffunction>
	
	<!--- --->
	
	<cffunction name="_CFHTTP" access="public" output="false" returntype="any">
		<cfargument name="url" required="true" />
		<cfargument name="type" required="true" />
		<cfargument name="timeout" required="false" default="15" />
		<cfargument name="contentType" required="true" />
		<cfargument name="authorization" required="true" />
		<cfargument name="args" required="true" />
		 
		<cfset var local = {} />
		
		<cfhttp url="#arguments.url#" charset="utf-8" method="#arguments.type#" timeout="#arguments.timeout#">
			<cfif arguments.contentType neq "">
				<cfhttpparam type="header" name="Content-Type" value="#arguments.contentType#" />
			</cfif>
			<cfif arguments.authorization neq "">
				<cfset local.authorizationValue = "Bearer #arguments.authorization#" />
				<cfhttpparam type="header" name="Authorization" value="#local.authorizationValue#" />
				<cfset local.result.params.Authorization = local.authorizationValue />
			</cfif>
			
			<cfif arguments.type eq 'POST' or arguments.type eq 'PUT'>
				<cfif arguments.contentType eq 'application/json'>
					<cfhttpparam type="body" value="#serializeJSON(arguments.args)#" />
					<cfloop collection="#arguments.args#" item="local.item">
						<cfset local.result.params[lcase(local.item)] = arguments.args[local.item] />
					</cfloop>
				<cfelseif arguments.contentType contains 'multipart/mixed'>
					<cfhttpparam type="body" value="#arguments.args.body#" />
				<cfelse>
					<cfloop collection="#arguments.args#" item="local.item">
						<cfhttpparam type="formfield" name="#lcase(local.item)#" value="#arguments.args[local.item]#" />
						<cfset local.result.params[lcase(local.item)] = arguments.args[local.item] />
					</cfloop>
				</cfif>
			</cfif>
		</cfhttp>
				
		<cfreturn cfhttp />

	</cffunction>
	
	<!--- --->


</cfcomponent>